import socket
import re
import time
import random
import string
from Package import *

class Protocol:
  
  def __init__(self, server):
    self.server     = server
    self.volgnummer = 0    

  # Aanroeper van deze functie moet leaves niet vast hebben, anders: deadlock
  def unique_name(self, name):      
    self.server.mutex_leaves.acquire()
    for leaf in self.server.leaves:
      if name.lower() == leaf['name'].lower():
        self.server.mutex_leaves.release()
        return False
    self.server.mutex_leaves.release()
    
    self.server.mutex_clients.acquire()
    for child in self.server.clients:
      if name.lower() == child['name'].lower():
        self.server.mutex_clients.release()
        return False
    self.server.mutex_clients.release()
    
    return True
  
  # handle input: take package and call method suitable for package
  def handle_input(self, package, addr):

    # Update the "last updated" timestamp for the sending node
    node = self.server.find_connected_node_by_addr(addr)
    if (node):
      node['last_updated'] = time.time()
    
    self.server.printdb("Selecting handler for a package with code: " \
                                                            + str(package.code)) 
    # call the right handle method
    if   package.code == 100: self.handle_100(package, addr)
    elif package.code == 110: self.handle_110(package, addr)
    elif package.code == 120: self.handle_120(package, addr)
    elif package.code == 130: self.handle_130(package, addr)
    elif package.code == 140: self.handle_140(package, addr)
    elif package.code == 150: self.handle_150(package, addr)
    elif package.code == 160: self.handle_160(package, addr)
    elif package.code == 170: self.handle_170(package, addr)
    elif package.code == 200: self.handle_200(package, addr)
    elif package.code == 210: self.handle_210(package, addr)
    elif package.code == 300: self.handle_300(package, addr)
    elif package.code == 310: self.handle_310(package, addr)
    elif package.code == 600: self.handle_600(package, addr)
    elif package.code == 602: self.handle_602(package, addr)
    elif package.code == 604: self.handle_604(package, addr)
    elif package.code == 700: self.handle_700(package, addr)
    elif package.code == 701: self.handle_701(package, addr)
    else: self.server.printdb("Unable to handle a " + str(package.code) \
                                       + " package, package ingnored.")

  # send package using the socket
  # servers will respond to the port of the socket,
  # so this has to be the same socket as for incoming packages
  def send_package(self, package, addr):
    self.server.socket.sendto(package.to_binary(), addr)
    self.volgnummer = self.volgnummer + 1

  # get list of all leaves, children and the parent
  def get_everything(self, addr = False):
    everything = list()
    
    self.server.mutex_parent.acquire()
    if self.server.parent != None:
      if addr:
        if self.server.parent['ip:port'] != addr:
          everything.append(self.server.parent)
      else:
        everything.append(self.server.parent)      
    self.server.mutex_parent.release()

    self.server.mutex_children.acquire()
    if self.server.children:
      everything.extend(self.server.children)
    self.server.mutex_children.release()
      
    self.server.mutex_leaves.acquire()
    if self.server.leaves:
      everything.extend(self.server.leaves)
    self.server.mutex_leaves.release()
    
    return everything
      
  def get_all_leaves(self):
    all_leaves = list()
    
    self.server.mutex_leaves.acquire()
    if self.server.leaves:
      all_leaves.extend(self.server.leaves)
    self.server.mutex_leaves.release()      

    self.server.mutex_clients.acquire()
    if self.server.clients:
      all_leaves.extend(self.server.clients)
    self.server.mutex_clients.release()
    
    return all_leaves

  def get_client_by_addr(self, addr):
    self.server.mutex_leaves.acquire()
    for leaf in self.server.leaves:
      if leaf['ip:port'] == addr:
        self.server.mutex_leaves.release()
        return leaf['name']             
    self.server.mutex_leaves.release()
    
    return False

  # send private message
  def whisper(self, sender, message, receiver, func, addr = False):
    done = False
    
    self.server.mutex_leaves.acquire()
    for leaf in self.server.leaves:
      if leaf['name'] == receiver:
        func(leaf['ip:port'], sender, message, receiver)
        done = True
        break
    self.server.mutex_leaves.release()

    if not done:
      self.server.mutex_parent.acquire()
      if self.server.parent != None:
        if addr:
          if self.server.parent['ip:port'] != addr:
            func(self.server.parent['ip:port'], sender, message, receiver)
        else:
          func(self.server.parent['ip:port'], sender, message, receiver)
      self.server.mutex_parent.release()

      self.server.mutex_children.acquire()
      for child in self.server.children:
        func(child['ip:port'], sender, message, receiver)
      self.server.mutex_children.release()


  ## Handle methods

  def handle_100(self, package, addr):
    name     = package.get_word(0)
    password = package.get_word(1)

    if not self.unique_name(name):
      self.server.printdb("Registration from " + str(addr) + " failed. " + name+ " is not a unique name")
      self.registration_failed_510(addr, "Registration failed: name already in use\n")
    elif name in self.server.admins and self.server.admins[name] != password:
      self.server.printdb("Registration from " + str(addr) + " failed. wrong password provided\n")
      self.registration_failed_510(addr, "Registration failed: wrong password provided")
    elif not re.match("^[A-Za-z0-9_]*$", name):
      self.server.printdb("Registration from " + str(addr) + " failed. " + name + " contains illegal name characters\n")
      self.registration_failed_510(addr, "Name may only consist of letters, numbers and underscores")
    else:
      self.server.mutex_leaves.acquire()
      self.server.leaves.append({'ip:port': addr, 'name': name, 'last_updated': time.time()})
      self.server.mutex_leaves.release()
      
      self.server.printdb("Client added as leaf with name: " + name + '\n')
      self.registration_accepted_500(addr)
      
      everything = self.get_everything()
      all_leaves = self.get_all_leaves()
     
      if everything:
        # Make sure the whole world knows about the new client, including himself
        for node in everything:
          self.client_added_110(node['ip:port'], 1, 1, name)
      
      if all_leaves:
        msg_counter = 1
          
        for node in all_leaves:
          # Now give the client a list of the whole world, but excluding himself since we got that fixed in step 1
          if node['ip:port'] != addr:
            self.client_added_110(addr, msg_counter, len(all_leaves) - 1, node['name'])
            msg_counter = msg_counter + 1
  
  def handle_110(self, package, addr):      
    content = package.get_word(0)
    current = content[0:6]
    length  = content[6:12]
    
    if int(length) == 0:
      return
      
    name  = content[12:]
    found = False
        
    # Get tag of server who send this
    server_tag = False
 
    self.server.mutex_parent.acquire()
    if self.server.parent != None:
      if self.server.parent['ip:port'] == addr:
        server_tag = self.server.parent['tag']
    self.server.mutex_parent.release()
    
    if not server_tag:
      self.server.mutex_children.acquire()
      for node in self.server.children:
        if node['ip:port'] == addr:
          server_tag = node['tag']
      self.server.mutex_children.release()

    # not found:
    if True:
      self.server.mutex_clients.acquire()
      self.server.clients.append({'ip:port':addr, 'name':name, 'last_updated': time.time(), 'server_tag':server_tag})
      self.server.mutex_clients.release()

      self.server.mutex_parent.acquire()
      if self.server.parent != None:
        if self.server.parent['ip:port'] != addr:
          self.client_added_110(self.server.parent['ip:port'], 1, 1, name)
      self.server.mutex_parent.release()

      self.server.mutex_children.acquire()
      for node in self.server.children:
        if node['ip:port'] != addr:
          self.client_added_110(node['ip:port'], 1, 1, name)
      self.server.mutex_children.release()
      
      # Give the clients an update too
      self.server.mutex_leaves.acquire()
      for node in self.server.leaves:
        self.client_added_110(node['ip:port'], 1, 1, name)
      self.server.mutex_leaves.release()
    else:
      self.server.printdb("Something went wrong with: " + name)
      
  def handle_120(self, package, addr):
    client  = self.server.find_connected_node_by_addr(addr)
    message = package.get_text(0)
       
    self.server.mutex_leaves.acquire()
    if client in self.server.leaves: 
      self.server.leaves.remove(client) # remove client from list
      self.server.mutex_leaves.release()
      self.server.printdb("Client: " + client['name'] + " left\n")

      everything = self.get_everything()
    
      if everything:
        for node in everything:
          self.removed_client_130(node['ip:port'], client['name'], message)
    else:
      self.server.mutex_leaves.release()
      self.server.printdb("A client with addr "+str(addr)+" wanted to disconnect, but wasn't connected to this server\n")

  def handle_130(self, package, addr):
    name    = package.get_word(0)
    message = package.get_text(1)
    
    # search for leaving client
    for leaf in self.server.clients:
      if leaf['name'] == name:
        self.server.mutex_clients.acquire()
        self.server.clients.remove(leaf)  # remove client from list
        self.server.mutex_clients.release()
        break

    # When a connection is ended, but not by the client itself:
    if len(message) < 1:
      message = "Leaving"

    everything = self.get_everything(addr)

    if everything:
      for node in everything:
        if node['ip:port'] != addr:
          self.removed_client_130(node['ip:port'], name, message)

  def handle_140(self, package, addr):
    self.pong_150(addr, package.get_word(0))

  def handle_150(self, package, addr):
    pass
    
  def handle_160(self, package, addr):
    new_name = package.get_word(0)
    # password while name changing not specified in given protocol
   
    if not re.match("^[A-Za-z0-9_]*$", new_name):
      self.name_change_failed_530(addr, "Name may only consist of letters, numbers or underscores")
      return
    
    # find old_name of client
    self.server.mutex_leaves.acquire()
    for leaf in self.server.leaves:
      if leaf['ip:port'] == addr:
        old_name = leaf['name']
        
        self.server.mutex_leaves.release()            # release for unique_name function
        not_unique = not (self.unique_name(new_name)) # wierd construction needed. Else u would call
        self.server.mutex_leaves.acquire()            # release() when you haven't locked it yet.

        if old_name == new_name:
          self.name_change_failed_530(addr, "Requested name is the same as your current name")
          break
        elif not_unique:
          self.name_change_failed_530(addr, "The requested name allready exists")
          break
        else:          
          leaf['name'] = new_name # save name change

          self.name_change_successfull_520(addr)
          
          # send name change to all connected servers and connected clients
          self.server.mutex_parent.acquire()
          if self.server.parent != None:
            self.name_changed_170(self.server.parent['ip:port'], old_name, new_name)
          self.server.mutex_parent.release() 
          
          self.server.mutex_children.acquire()
          for node in self.server.children:
            self.name_changed_170(node['ip:port'], old_name, new_name)
          self.server.mutex_children.release()

          # Don't forget the person himself so he gets an updated list too
          for leaf in self.server.leaves:
            self.name_changed_170(leaf['ip:port'], old_name, new_name)
              
    self.server.mutex_leaves.release()

  def handle_170(self, package, addr):
    old_name = package.get_word(0)
    new_name = package.get_word(1)
    
    self.server.mutex_clients.acquire()
    for leaf in self.server.clients:
      if leaf['name'] == old_name:
        leaf['name'] = new_name
    self.server.mutex_clients.release()
    
    everything = self.get_everything(addr)

    self.server.mutex_leaves.acquire()    
    if everything:
      for node in everything:
        if node['ip:port'] != addr: 
          self.name_changed_170(node['ip:port'], old_name, new_name)
    self.server.mutex_leaves.release()

  def handle_200(self, package, addr):
    self.handle_200_210(package, addr, self.pass_text_message_300)

  def handle_210(self, package, addr):
    self.handle_200_210(package, addr, self.pass_action_310)
   
  def handle_200_210(self, package, addr, func):
    sender = None

    self.server.mutex_leaves.acquire() 
    for leaf in self.server.leaves:
      if leaf['ip:port'] == addr:
        sender = leaf['name']
    self.server.mutex_leaves.release()

    if sender == None:
      self.server.printdb("Unknown client wants to send a message.")
      return
    
    receiver = package.get_word(0)
    message  = package.get_text(1)

    if receiver == "#all":
      everything = self.get_everything()

      self.server.mutex_leaves.acquire()
      if everything:      
        for node in everything:
          func(node['ip:port'], sender, message, '#all')
      self.server.mutex_leaves.release()
    else:
      func(addr, sender, message, sender)
      self.whisper(sender, message, receiver, func, addr)

  def handle_300(self, package, addr):    
    self.handle_300_310(package, addr, self.pass_text_message_300)

  def handle_310(self, package, addr):
    self.handle_300_310(package, addr, self.pass_action_310)


  def handle_300_310(self, package, addr, func):

    sender   = package.get_word(0)
    receiver = package.get_word(1)
    message  = package.get_text(2)
    
    if receiver == "#all":
      everything = self.get_everything()

      self.server.mutex_leaves.acquire()
      if everything:      

        for node in everything:
          if node['ip:port'] != addr:
            func(node['ip:port'], sender, message, '#all')
      self.server.mutex_leaves.release()
    else:
      self.whisper(sender, message, receiver, func, addr)
  
  def handle_600(self, package, addr):    
    # voeg server toe aan lijst
    print "Nieuwe server als child: " + package.get_word(0)
    
    self.server.mutex_children.acquire()
    self.server.children.append({'ip:port': addr, 'tag': package.get_word(0), 'last_updated': time.time()})
    self.server.mutex_children.release()
    
    all_leaves = self.get_all_leaves()
    
    msg_counter = 1

    # send own client list to new child
    for leaf in all_leaves:
      self.client_added_110(addr, msg_counter, len(all_leaves) - 1, leaf['name'])
      msg_counter = msg_counter + 1

    if all_leaves:
      msg_counter = 1
          
      for node in all_leaves:
         # Now give the client a list of the whole world, but excluding himself since we got that fixed in step 1
        if node['ip:port'] != addr:
          self.client_added_110(addr, msg_counter, len(all_leaves) - 1, node['name'])
          msg_counter = msg_counter + 1
    else:
      self.client_added_110(addr, 0, 0)

  def handle_602(self, package, addr):    
    # 604 kan 602 doorsturen :)
    if isinstance(package, basestring):
      temp = package
    else:
      temp = package.get_word(0)

    if temp == 'none':
      self.server.printdb("Server initialized as root\n")
    else:
      pack = temp.split(':')
      print "dit is pack: " + str(pack)
      self.server.mutex_parent.acquire()
      self.server.parent = {'ip:port': (pack[0], int(pack[1])), 'tag': pack[2], 'volgnummer': 0, 'last_updated': time.time()}
      self.server.mutex_parent.release()
      self.register_server_600((pack[0], int(pack[1])), self.server.tag)
      self.server.printdb("Server: " + self.server.parent['tag'] + " set as parent\n")
      
      # send all clients that I've got
      all_leaves = self.get_all_leaves()
      
      if all_leaves:
        print "Ik print nu alle namen die ik zou moeten versturen! " + str(all_leaves) 
        msg_counter = 1
          
        for node in all_leaves:
          print "En nu stuur ik: " + str(node['name'])
          self.client_added_110((pack[0], int(pack[1])), msg_counter, len(all_leaves) - 1, node['name'])
          msg_counter = msg_counter + 1
      else:
        self.client_added_110((pack[0], int(pack[1])), 0, 0)

  def handle_604(self, package, addr):
    fallen_server = package.get_word(0)
    tag           = package.get_word(1) # Could be empty
    
    # Update client list
    self.server.mutex_clients.acquire()
    self.server.mutex_leaves.acquire()
    self.server.mutex_children.acquire()
    self.server.mutex_parent.acquire()
        
    to_remove = list()
    
    if self.server.clients:
      for client in self.server.clients:  
        if client['server_tag'] == fallen_server:  
          # Make sure chat clients can update their list too
          if self.server.leaves:
            for leaf in self.server.leaves:
              self.removed_client_130(leaf['ip:port'], client['name'], 'Server disconnect')
          
          # Make sure children servers update their list too
          if self.server.children:
            for node in self.server.children:
              if node['tag'] != fallen_server:
                self.removed_client_130(node['ip:port'], client['name'], 'Server disconnect')
          
          if self.server.parent != None and self.server.parent['tag'] != fallen_server:
            self.removed_client_130(self.server.parent['ip:port'], client['name'], 'Server disconnect')
            
          to_remove.append(client)
          
      for element in to_remove:
        self.server.clients.remove(element)
      
    self.server.mutex_parent.release()
    self.server.mutex_children.release()
    self.server.mutex_leaves.release()
    self.server.mutex_clients.release()
    
    if tag:
      self.server.parent = None
      self.server.printdb("GETTING A NEW PARENT tag: " + str(tag))
      self.handle_602(tag, addr)
    else:
      to_remove = list()
      
      if self.server.children:
        for node in self.server.children:
          if node['tag'] == fallen_server:
            to_remove.append(node)
            
      for element in to_remove:
        self.server.children.remove(element)
  
  def handle_700(self, package, addr):
    # Check if invoked by admin
    self.server.mutex_leaves.acquire()
    for leaf in self.server.leaves:
      if leaf['ip:port'] == addr:
        if leaf['name'] in self.server.admins:
          # TODO
          #self.quit_701()
          self.server.stop()
        break
    self.server.mutex_leaves.release()
    
  def handle_701(self, package, addr): 
    # Get disconnecting server
    server = self.server.find_connected_node_by_addr(addr) 
    msg    = "Server: " + server['tag'] + " disconnected." 
    self.server.printdb(msg)
    self.peer_server_disconnect_603(self.central_server['ip:port'], server['tag'])
    
  # Aan de toegevoegde client of server wordt  in een serie berichten van dit 
  # type alle namen van verbonden clienten doorgegeven. Omdat deze boodschappen 
  # ook worden gebruikt om een reeks namen door te geven, wordt een volgnummer 
  # en een totaal aantal te versturen elementen meegegeven. Volgnummers lopen 
  # van 1 - lijstlengte. Gebruik voor de getallen een veldbreedte van 6 tekens. 
  # Bij de aanmelding van een server moeten ook dergelijke boodschappen worden 
  # uitgewisseld (zie verderop). Omdat er niet altijd clienten zullen zijn, 
  # mogen dan volgnummer en lijstlengte beide nul te zijn.
  def client_added_110(self, target, serial_number, list_length, name = None):
    msg = "Sending a 110 to: " + str(target)        + \
                " with name: " + str(name)          + \
                  ", serial: " + str(serial_number) + \
          " and list length: " + str(list_length)
    self.server.printdb(msg)
    
    package = Package(110, self.volgnummer)
    if name:
      package.add_word(str(serial_number).zfill(6) + str(list_length).zfill(6) + name)
    else:
      package.add_word(str(serial_number).zfill(6) + str(list_length).zfill(6))
    self.send_package(package, target)
    
  # Dit bericht wordt verzonden als de client-server verbinding verbroken is. 
  # De rest van het bericht bevat de naam van de verwijderde client en een tekst
  # die naar iedereen als groet verzonden wordt. Mocht de client deze niet zelf
  # invullen of wordt de verbinding onverwachts verbroken dan dient de server 
  # dit zelf in te vullen.
  def removed_client_130(self, target, name, message = None):
    msg = "Sending a 130 to: " + str(target)  + \
                " with name: " + str(name)    + \
              " and message: " + str(message)
    self.server.printdb(msg)
    
    package = Package(130, self.volgnummer)
    package.add_word(name)
    package.add_word(message)
    self.send_package(package, target)
    
  # De rest van het bericht dient 1 woord  te bevatten: een identificatie 
  # nummer tekenreeks. Het antwoord op dit bericht dient binnen 2 seconden
  # verstuurd te zijn, anders mag de verbinding verbroken worden. Omdat met UDP 
  # wordt gewerkt, is het niet altijd zeker of berichten aankomen. Daarom mag 
  # indien geen  pong wordt ontvangen, het ping-verzoek een paar keer worden 
  # herhaald met hetzelfde identificatienummer.
  def ping_140(self, target):
    id = self.generate_ping_tag()
    msg = "Sending a 140 to: " + str(target) + \
                  " with id: " + str(id)
    self.server.printdb(msg) 
    package = Package(140, self.volgnummer)
    package.add_word(id)
    self.send_package(package, target)

  # De rest van het bericht dient 1 woord te bevatten: het identificatienummer / 
  # tekenreeks van het voorafgaande Echo Request. Bericht dient binnen 2 sec na
  # het ontvangen van een ping verstuurd te zijn, anders mag de verbinding 
  # verbroken worden door de andere partij.
  def pong_150(self, target, echo_request):
    msg =   "Sending a 150 to: " + str(target)       + \
          " with echo request: " + str(echo_request)
    self.server.printdb(msg)
    package = Package(150, self.volgnummer)
    package.add_word(echo_request)
    self.send_package(package, target)

  # Dit bericht wordt aan alle aangesloten clienten verzonden als een client 
  # zijn naam heeft gewijzigd. Het eerste woord in het datadeel is de oude naam, 
  # het tweede de nieuwe naam.
  def name_changed_170(self, target, old_name, new_name):
    msg = "Sending a 170 to: " + str(target)   + \
            " with old name: " + str(old_name) + \
             " and new name: " + str(new_name)
    self.server.printdb(msg)
    package = Package(170, self.volgnummer)
    package.add_word(old_name)
    package.add_word(new_name)
    self.send_package(package, target)

  # De rest van het bericht bestaat uit 3 delen: het eerste woord is de naam van
  # de afzender, het tweede woord is de naam van degene aan wie het bericht 
  # gericht is of de tekst #all als het bericht naar iedereen gaat. De rest is 
  # de door de persoon ingevoerde tekst.
  def pass_text_message_300(self, target, sender, message, receiver = None):
    msg = "Sending a 300 to: " + str(target)   + \
              " with sender: " + str(sender)   + \
                 ", message: " + str(message)  + \
             " and receiver: " + str(receiver) 
    self.server.printdb(msg)
    package = Package(300)
    package.add_word(sender)
    if (receiver == None):
      package.add_word("#all")
    else:
      package.add_word(receiver)
    package.add_word(message)
    self.send_package(package, target)
     
  def pass_action_310(self, target, sender, message, receiver = None):
    msg = "Sending a 310 to: " + str(target)   + \
              " with sender: " + str(sender)   + \
                 ", message: " + str(message)  + \
             " and receiver: " + str(receiver) 
    self.server.printdb(msg)
    package = Package(310)
    package.add_word(sender)
    if (receiver == None):
      package.add_word("#all")
    else:
      package.add_word(receiver)
    package.add_word(message)
    self.send_package(package, target)
  
  # Wordt verzonden als de registratie gelukt is, de rest van het bericht kan 
  # leeg zijn.
  def registration_accepted_500(self, target):
    msg = "Sending a 500 to: " + str(target)
    self.server.printdb(msg)
    package = Package(500, self.volgnummer)
    self.send_package(package, target)

  # Wordt verzonden als de registratie mislukt is. De rest van het bericht bevat
  # de reden van het mislukken van de inlogpoging.
  def registration_failed_510(self, target, message):
    msg = "Sending a 510 to: " + str(target)  + \
             " with message: " + str(message)
    self.server.printdb(msg)
    package = Package(510)
    package.serial = 1 # TODO Echte serial! 
    package.add_word(message)
    self.send_package(package, target)
    
  # Wordt verzonden als de naamswijziging gelukt is, de rest van het bericht kan
  # leeg zijn.
  def name_change_successfull_520(self, target):
    msg = "Sending a 520 to: " + str(target)
    self.server.printdb(msg)
    package = Package(520)
    self.send_package(package, target)
    
  # Wordt verzonden als de naamswijziging mislukt is. De rest van het bericht 
  # bevat de reden van het mislukken van de pogin.
  def name_change_failed_530(self, target, message):
    msg = "Sending a 530 to: " + str(target)  + \
             " with message: " + str(message)
    self.server.printdb(msg)
    package = Package(530)
    package.add_word(message)
    self.send_package(package, target)
  
  # Dit verstuurt een server om zich aan te melden bij een andere server. Het is
  # dus de server-server versie van berichtype 100. De ontvangende server moet 
  # ip adres en poortnummer van de afzender uit de ip header halen.
  def register_server_600(self, target, tag):
    msg = "Sending a 600 to: " + str(target) + \
                 " with tag: " + str(tag)
    self.server.printdb(msg)
    package = Package(600, self.volgnummer)
    package.add_word(tag)
    self.send_package(package, target)

  # Dit verstuurt een server bij aanmelding naar de control server. De 
  # ontvangende server moet ip adres en poortnummer van de afzender uit de ip 
  # header halen.
  def hello_to_control_601(self, target, tag):
    msg = "Sending a 601 to: " + str(target) + " with tag: " + str(tag)
    self.server.printdb(msg)
    package = Package(601, self.volgnummer)
    package.add_word(tag)
    self.send_package(package, target)
  
  # Dit verstuurt een server naar de control server als een van zijn partner 
  # servers niet reageert. Dat kan dus de parent of een van de kinderen zijn. De
  # huidige implementatie van de control server neemt een 603 altijd voor waar 
  # aan en probeert niet of de betreffende server misschien toch reageert.    
  def peer_server_disconnected_603(self, target, tag):
    msg = "Sending a 603 to: " + str(target) + \
                 " with tag: " + str(tag)
    self.server.printdb(msg)
    package = Package(603)
    package.add_word(tag)
    self.send_package(package, target)

  # Een server kan dit bericht versturen naar  zijn buren als hij gaat stoppen, 
  # b.v. na de ontvangst van een 700 bericht.
  def quit_701(self, target, message):
    msg = "Sending a 701 to: " + str(target)  + \
             " with message: " + str(message)
    self.server.printdb(msg)
    package = Package(701)
    package.add_word(message)
    self.send_package(package, target)
    
  def generate_ping_tag(self):
    temp = ""
    for i in xrange(15):
      temp += random.choice(string.letters + string.digits)
    return temp
